package pacs.sgc.dao;

import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import pacs.sgc.classesbasicas.Cliente;
import pacs.sgc.classesbasicas.Endereco;
import pacs.sgc.exceptions.AcessoAoBancoException;
import pacs.sgc.exceptions.ConexaoComBancoException;

public class ClienteDao implements IClienteDao {
	private Conexao conexao;
	private PreparedStatement statement = null;
	private ResultSet rs = null;
	
	private EnderecoDao enderecoDao = FabricaDao.criarEnderecoDao();

	private final String SQL_INSERT = "INSERT INTO cliente(codigo, nome, cpf, rg, dataNascimento, codEndereco, telefone, celular, email) " +
			"VALUES(?,?,?,?,?,?,?,?,?)"; //9 parametros	
	private final String SQL_DELETE = "DELETE FROM cliente WHERE cpf = ?";
	private final String SQL_UPDATE = "UPDATE cliente SET nome = ?, cpf = ?, rg = ?, dataNascimento = ?, codEndereco = ?, " +
			"telefone = ?, celular = ?, email = ? WHERE codigo = ?";
	private final String SQL_SELECT = "SELECT codigo, nome, cpf, rg, dataNascimento, codEndereco, telefone, celular, email FROM cliente WHERE cpf = ? OR rg = ?";
	private final String SQL_SELECT_CODIGO = "SELECT codigo, nome, cpf, rg, dataNascimento, codEndereco, telefone, celular, email FROM cliente WHERE codigo = ?";
	private final String SQL_SELECT_TODOS = "SELECT codigo, nome, cpf, rg, dataNascimento, codEndereco, telefone, celular, email FROM cliente";
	private final String SQL_SELECT_ULTIMO = "SELECT codigo FROM cliente WHERE codigo = (SELECT MAX(codigo) FROM cliente)";

	
	
	/**
	 * Construtor Default
	 *
	 */
	public ClienteDao(){
		this.conexao = FabricaConexao.criarConexao();
	}
	
	
	/**
	 * Construtor
	 * 
	 * @param conexao
	 */
	public ClienteDao(Conexao conexao){
		this.conexao = conexao;
	}
	
	
	/**
	 * Metodo que atualiza um cliente existente
	 * 
	 * @param atualizado
	 * @return void
	 * @throws ConexaoComBancoException
	 * @throws AcessoAoBancoException
	 */
	public void atualizar(Cliente atualizado) throws ConexaoComBancoException, AcessoAoBancoException {
		PreparedStatement update = null;
		try{
			this.conexao.abrirConexao();
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_SELECT_CODIGO);
			this.statement.setInt(1,atualizado.getCodigo());
			this.rs = statement.executeQuery();
			
			if(rs.next()){
				update = this.conexao.getCon().prepareStatement(this.SQL_UPDATE);
				
				update.setString(1, atualizado.getNome());
				update.setString(2, atualizado.getCpf());
				update.setString(3, atualizado.getRg());
				update.setDate(4, atualizado.getDataNascimento());
				update.setInt(5, atualizado.getEndereco().getCodigo());
				update.setString(6, atualizado.getTelefone());
				update.setString(7, atualizado.getCelular());
				update.setString(8, atualizado.getEmail());
				update.setInt(9, atualizado.getCodigo());
				
				update.execute();
				update.close();				
			}
		}catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{			
			try {
				if(this.conexao != null)
					this.conexao.fecharConexao();
				
				if(this.statement != null)
					this.statement.close();
				
				if(this.rs != null)
					this.rs.close();
				
				if(update != null)
					update.close();
			} catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}
	}

	
	/**
	 * Metodo que pega do banco o ultimo codigo inserido na tabela cliente e 
	 * gera o proximo codigo a ser inserido
	 * 
	 * @return int;
	 * @throws AcessoAoBancoException
	 * @throws ConexaoComBancoException
	 */
	public int gerarCodigo() throws ConexaoComBancoException, AcessoAoBancoException {
		int proximoCodigo = 1;
		try{
			this.conexao.abrirConexao();
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_SELECT_ULTIMO);
			
			this.rs = statement.executeQuery();
			
			if(this.rs.next())
				proximoCodigo = rs.getInt("codigo") + 1;
			
		} catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{			
			try {
				if(this.conexao != null)
					this.conexao.fecharConexao();
				
				if(this.statement != null)
					this.statement.close();
				
				if(this.rs != null)
					this.rs.close();
			} catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}
		return proximoCodigo;
	}

	
	/**
	 * Metodo que insere um novo registro na tabela cliente.
	 * 
	 * @param novoCliente
	 * @return void
	 * @throws AcessoAoBancoException
	 * @throws ConexaoComBancoException
	 */
	public void inserir(Cliente novoCliente) throws ConexaoComBancoException, AcessoAoBancoException {
		try{
			this.conexao.abrirConexao();
			
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_INSERT);
			this.statement.setInt(1, novoCliente.getCodigo());
			this.statement.setString(2, novoCliente.getNome());
			this.statement.setString(3, novoCliente.getCpf());
			this.statement.setString(4, novoCliente.getRg());
			this.statement.setDate(5, novoCliente.getDataNascimento());
			this.statement.setInt(6, novoCliente.getEndereco().getCodigo());
			this.statement.setString(7, novoCliente.getTelefone());
			this.statement.setString(8, novoCliente.getCelular());
			this.statement.setString(9, novoCliente.getEmail());
			
			this.statement.execute();
		} catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{
			try{
				if(this.conexao != null)
					this.conexao.fecharConexao();
				if(this.statement != null)
					this.statement.close();	
			}catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}
	}

	
	/**
	 * Metodo que lista todos os clientes cadastrado
	 * 
	 * @return List<Cliente>
	 * @throws AcessoAoBancoException 
	 * @throws ConexaoComBancoException 
	 */
	public List<Cliente> listar() throws ConexaoComBancoException, AcessoAoBancoException {
		List<Cliente> listaDeClientes = new ArrayList<Cliente>();
		try{
			this.conexao.abrirConexao();
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_SELECT_TODOS);			
			this.rs = this.statement.executeQuery();
			
			while(rs.next()){
				int codigo = this.rs.getInt(1);
				String nome = this.rs.getString(2);
				String cpf = this.rs.getString(3);
				String rg = this.rs.getString(4);
				Date dataNascimento = this.rs.getDate(5);
				Endereco endereco = enderecoDao.localizar(this.rs.getInt(6));
				String telefone = this.rs.getString(7);
				String celular = this.rs.getString(8);
				String email = this.rs.getString(9);
				
				listaDeClientes.add(new Cliente(codigo,nome,cpf,rg,dataNascimento,endereco,telefone,celular,email));
			}
			
		}catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{			
			try {
				if(this.conexao != null)
					this.conexao.fecharConexao();
				
				if(this.statement != null)
					this.statement.close();
				
				if(this.rs != null)
					this.rs.close();
			} catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}
		return listaDeClientes;
	}
	
	
	/**
	 * Metodo que localiza um cliente apartir do seu cpf ou do seu rg.
	 * 
	 * @param cpf
	 * @param rg
	 * @return Cliente
	 * @throws AcessoAoBancoException 
	 * @throws ConexaoComBancoException 
	 */
	public Cliente localizar(String cpf, String rg) throws ConexaoComBancoException, AcessoAoBancoException {
		Cliente localizado = null;
		try{
			this.conexao.abrirConexao();
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_SELECT);	
			this.statement.setString(1, cpf);
			this.statement.setString(2, rg);
			this.rs = this.statement.executeQuery();
			
			if(rs.next()){
				int codigo = this.rs.getInt(1);
				String nome = this.rs.getString(2);
				String cpf2 = this.rs.getString(3);
				String rg2 = this.rs.getString(4);
				Date dataNascimento = this.rs.getDate(5);
				Endereco endereco = enderecoDao.localizar(this.rs.getInt(6));
				String telefone = this.rs.getString(7);
				String celular = this.rs.getString(8);
				String email = this.rs.getString(9);
				
				localizado = new Cliente(codigo,nome,cpf2,rg2,dataNascimento,endereco,telefone,celular,email);
			}
			
		}catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{			
			try {
				if(this.conexao != null)
					this.conexao.fecharConexao();
				
				if(this.statement != null)
					this.statement.close();
				
				if(this.rs != null)
					this.rs.close();
			} catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}
		return localizado;
	}

	/**
	 * Metodo que remove um registro da tabela cliente que tenha o cpf igual ao cpf passado.
	 * 
	 * @param cpf
	 * @return void
	 * @throws AcessoAoBancoException
	 * @throws ConexaoComBancoException
	 */
	public void remover(String cpf) throws ConexaoComBancoException, AcessoAoBancoException {
		try{
			this.conexao.abrirConexao();
			
			this.statement = this.conexao.getCon().prepareStatement(this.SQL_DELETE);
			this.statement.setString(1, cpf);
			this.statement.execute();
			
		}catch (SQLException e) {
			AcessoAoBancoException e1 =
				new AcessoAoBancoException();
			throw e1;			
		} catch (ClassNotFoundException e) {
			ConexaoComBancoException e1 =
				new ConexaoComBancoException();
			throw e1;
		}finally{
			try{
				if(this.conexao != null)
					this.conexao.fecharConexao();
				if(this.statement != null)
					this.statement.close();	
			}catch (SQLException e) {
				AcessoAoBancoException e1 =
					new AcessoAoBancoException();
				throw e1;
			}
		}
	}

}
